#include "jadro.h"
#include "lex_an.h"
//#include "pamet.h"
#include "synt_an.h"
//#include <stdio.h>
#include "q_io.h"

//#include "over.cpp" //vyhodnocovani podminek v ramci behu

Retezec* retezce=NULL;

Retezec::~Retezec()
      { if(obsah) delete obsah;
        if(dal) dal->nzpet(zpet);
	if(zpet) zpet->ndal(dal); else retezce=dal; }

void vypisretezcu()
{
  Retezec* r=retezce;
  while(r)
  {
    printf("(%d) %s\n",r->vpoc(),r->vobsah());
    r=r->dalsi();
  }
}

Retezec* kretezec(char* o)
{
  Retezec* r=retezce;
  while(r)
  {
    if(!strcmp(r->vobsah(),o))
     { r->zvys(); return r; }
    r=r->dalsi();
  }
  r=new Retezec(o);
  malopameti(r);
  r->ndal(retezce);
  if(retezce) retezce->nzpet(r);
  retezce=r;
  return r;
}

Qhrana::~Qhrana()
{
//  puts("! >>> DELETING hrana <<< !"); test();
  if(vetev1) vetev1->pocminus();
  if(retez1 && !vetev2) retez1->pocminus();
  if(strom) strom->pocminus();
}

Qstrom::Qstrom(Qstrom* a)
{
  if(a->konst)
  {
    desint=a;
    jmeno=NULL;
    syn=bratr=dalsi=NULL;
    konst=_Ldekompozice; poc=1;
  } else {
    char* atom=a->vobsah();
    //obsah=new char[2]; //alok++;
    //malopameti(obsah);
    //strncpy(obsah,atom,1);
    //obsah[1]=0;
    char c=atom[1];
    atom[1]=0;
    jmeno=new Retezec(atom);
    atom[1]=c;
    syn=bratr=dalsi=NULL;
    konst=0; poc=1; desint=NULL;
    Qstrom *s=this;
    for(int i=1;atom[i];i++)
    {
      char c=atom[i+1];
      atom[i+1]=0;
      Qstrom* v=new Qstrom(atom+i,0);
      malopameti(v);
      atom[i+1]=c;
      s->nbratr(v);
      s=v;
    }
    delete a;
  }
}

Qstrom::~Qstrom()
{
//  puts("! >>> DELETING strom <<< !"); test();
  if(syn) syn->pocminus();
  if(bratr) bratr->pocminus();
  //if(obsah) { delete[] obsah; /*alok--;*/ }
  if(jmeno) jmeno->zrus();
  if(desint) desint->pocminus();
}


void Qprogram::pripoj(Qprogram* qp)
{
  Qfaze* qf=faze();
  while(qf->dal()) qf=qf->dal();
  qf->nastav(qp->faze());
  qp->nfaze(NULL);
  delete qp;
}

Qpravidlo *Qprogram::edpravidlo(char* soub,unsigned long rad,unsigned long slp)
{
  if(_faze) return _faze->edpravidlo(soub,rad,slp);
  else return NULL;
}

Qpravidlo *Qfaze::edpravidlo(char* soub,unsigned long rad,unsigned long slp)
{
  Qpravidlo* p=prav;
  while(p)
  {
    if(!stricmp(p->soubor,soub) &&
       (rad>p->rad1 && rad<p->rad2  ||
        rad==p->rad1 && slp>=p->slp1 ||
        rad==p->rad2 && slp<=p->slp2)) return p;
    p=p->dal();
  }
  if(dal()) return dal()->edpravidlo(soub,rad,slp);
  else return NULL;
}
    
/*
void Qstrom::test(FILE* file,int typ,int dlk)
{
  if(konst==_Lnul) QFILE<<"-NUL-";
  else if(konst==_Ldekompozice) { QFILE<<"$$"; desint->test(file); }
  else {
    QFILE<<(jmeno?vobsah():(char*)"!!!NULLovy string!!!");
    if(konst) QFILE<<"*";
  }
  if(typ!=_Latomovapromenna && vsyn())
  {//upravil OA
    QFILE<<"(";
    vsyn()->test(file,_Lseznamovapromenna,-1);
    QFILE<<")";
  }
  if(!dlk) return;
  if(dlk!=-1) dlk--;
  if(typ==_Lseznamovapromenna && vbratr()) { QFILE<<","; vbratr()->test(file,_Lseznamovapromenna,dlk); }
//  if(retez1) { fprintf(file," + "); retez1->test(file); }
}

void Qhrana::test(FILE* file)
{
  vstrom()->test(file);
  if(vretez1())
  {
    QFILE<<" + ";
    vretez1()->test(file);
  }
}

void Qstrom::test3(FILE* file)
{
  if(konst==_Lnul) fprintf(file,"-NUL-");
  else if(konst==_Ldekompozice) { QFILE<<"$$"; desint->test(file); }
  else {
    QFILE<<(jmeno?vobsah():(char*)"!!!NULLovy string!!!");
    if(konst) QFILE<<"*";
  }
  if(vsyn())
  {
    Qstrom* s=vsyn();
    QFILE<<"(";
    s->test(file);//upravil OA
    QFILE<<")";
  }
//  if(retez1) { fprintf(file," + "); retez1->test(); }
}

static void vypispredek(Qhrana* qu,FILE* file,int posl=0)
{
  if(qu)
  {
    vypispredek(qu->dal(),file);
    //qu->ndalsi(NULL);
    qu->vstrom()->test3(file);
    QFILE<<(posl?(char*)endl:(char*)" + ")<<(posl?(char*)endl:(char*)"");
  }
}

static void vypiszbytek(Qhrana* qu,FILE* file)
{
  Qhrana* qv=qu->vretez1();
  if(!qv) vypispredek(qu,file,1);
  else while(qv)
  {
    qv->ndalsi(qu);
    vypiszbytek(qv,file);
    qv=qv->vvetev1();
  }
}

void Qhrana::test4(FILE* file)
{
  Qhrana* qu=this;
  while(qu)
  {
    qu->ndalsi(NULL);
    vypiszbytek(qu,file);
    qu=qu->vvetev1();
  }
}

void Qhrana::test2old(FILE* file,int pospojovat)
{
  //volnapamet("Zacatek vypisu");
  struct Hrana { Qhrana* qu; int zac,kon,presk,pok; Hrana* dal; };
  struct Uzel { Qhrana* qu; Uzel* zas; };
  Hrana *hpoc=NULL,*hpos=NULL;
  int maxu=2;
  Uzel* zas=new Uzel;
  malopameti(zas);
  zas->qu=this; zas->zas=NULL; Uzel* zas2=zas;
  Qhrana* qu=this->vvetev1();
  //volnapamet("Pred 1. vytvarenim zasobniku");
  while(qu)
  {
    Uzel* u=new Uzel;
    malopameti(u);
    u->qu=qu; u->zas=NULL;
    zas2->zas=u; zas2=u;
    qu=qu->vvetev1();
  }
  while(zas)
  {
    Qhrana* qu=zas->qu;
    Uzel* u=zas;
    zas=zas->zas;
    delete u;
    qu->nurov(0);
    qu->npouz(0);
    Qhrana* pu=qu->vretez1();
    while(pu)
    {
      Uzel* nu=new Uzel;
      malopameti(nu);
      nu->qu=pu; nu->zas=NULL;
      if(!zas) zas=zas2=nu;
      else { zas2->zas=nu; zas2=nu; }
      pu=pu->vvetev1();
    }
  }
  //volnapamet("Po 1. zpracovani zasobniku");

  zas=new Uzel;
  malopameti(zas);
  zas->qu=this; zas->zas=NULL; zas2=zas;
  qu=this->vvetev1();/**
  //volnapamet("Pred 2. vytvarenim zasobniku");
  while(qu)
  {
    Uzel* u=new Uzel;
    malopameti(u);
    u->qu=qu; u->zas=NULL;
    zas2->zas=u; zas2=u;
    qu=qu->vvetev1();
  }
  while(zas)
  {
    Qhrana* qu=zas->qu;
    Uzel* u=zas;
    zas=zas->zas;
    delete u;
    //printf("%d ",maxu); //////////////////////////
    if(!qu->urov)
    {
      Qhrana* qv=qu;
      //int pm=0;
      while(qv)
      {
	/*if(!qv->vurov()) {/** qv->nurov(maxu); //}
	qv=qv->vvetev2();
      }
      maxu++;
      Qhrana* pu=qu->vretez1();
      while(pu)
      {
	Uzel* nu=new Uzel;
	malopameti(nu);
	nu->qu=pu; nu->zas=NULL;
	/*if(!zas) zas=zas2=nu;
	else { zas2->zas=nu; zas2=nu; }/**
	if(!zas) zas=nu; else { nu->zas=zas; zas=nu; }
	pu=pu->vvetev1();
      }
    }
  }
  //volnapamet("Po 2. zpracovani zasobniku");

  //int maxu=2;
  /********************
  puts(retez1?"1":"0");
  puts(retez2?"1":"0");
  /** ///////////////////
  zas=new Uzel;
  malopameti(zas);
  zas->qu=this; zas->zas=NULL; zas2=zas;
  qu=this->vvetev1();
  while(qu)
  {
    Uzel* u=new Uzel;
    malopameti(u);
    u->qu=qu; u->zas=NULL;
    zas2->zas=u; zas2=u;
    u->qu->npouz(1);
    qu=qu->vvetev1();
  }
  while(zas)
  {
    Uzel* u=zas;
    zas=zas->zas;
    Qhrana* qu=u->qu;
    delete u;
//    printf("UZEL: %s, %d\n",qu->vobsah(),qu->vurov());
    /*while(qu)
    {/**
    Hrana* h=new Hrana;
    malopameti(h);
    h->qu=qu; h->dal=NULL;
    if(!h->qu->vretez2()) h->zac=1; else h->zac=h->qu->vretez2()->vurov();
    h->kon=h->qu->vurov();
      /*Hrana* g=hpoc;
      while(g)
      {
	if(h->qu->vvetev2()==g->qu || g->qu->vvetev2()==h->qu || g->qu==h->qu)
	 { h->kon=g->kon; break; }
	g=g->dal;
      }
      int nv=!h->kon;
      if(!h->kon) h->kon=maxu++;/**
    if(!hpoc) hpoc=hpos=h; else { hpos->dal=h; hpos=h; }
      /*if(nv && qu->vretez1())
      {
	Uzel* v=new Uzel;
	malopameti(v);
	v->qu=qu->vretez1(); /*v->poc=h->kon;/**/ /*v->zas=NULL;
	if(zas) { zas2->zas=v; zas2=v; }
	else zas=zas2=v; //v->zas=zas; zas=v;
      }
      qu=qu->vvetev1();
    }/**
    Qhrana* pu=qu->vretez1();
    while(pu)
    {
      if(!pu->vpouz())
      {
	Uzel* nu=new Uzel;
	malopameti(nu);
	nu->qu=pu; nu->zas=NULL; nu->qu->npouz(1);
	if(!zas) zas=zas2=nu;
	else { zas2->zas=nu; zas2=nu; }
      }
      pu=pu->vvetev1();
    }
  }/**/
  //volnapamet("Po 3. zpracovani zasobniku (alokace hran)");

/*  puts("/--------------------------------------------/");
  Hrana* h1=hpoc;
  while(h1)
  {
    printf("Hrana: %s (%d), %d, %d\n",h1->qu->vobsah(),h1->qu->vurov(),h1->zac,h1->kon);
    h1=h1->dal;
  }
  return;/**
  // Pokud se nejaka cesta nevetvi, hrany se pospojuji do retezce

  if(pospojovat)
  {
    struct Pom { int poc; Qhrana *qu; Hrana* hr; };
    Pom* pom1=new Pom[maxu];
    malopameti(pom1);
    Pom* pom2=new Pom[maxu];
    malopameti(pom2);
//    int *pouz=new[maxu+1],*zamena=new[maxu+1],i,konec;    // Pro precislovani
//    for(i=1;i<maxu;i++) { pouz[i]=1; zamena[i]=0; }   // Pro precislovani
    for(int i=1;i<maxu;i++) pom1[i].poc=pom2[i].poc=0;
    Hrana* h=hpoc;
//    fprintf(file,"maxu: %d\n",maxu); /*!!!!!!!!!!!!!!!!!!!!!*
    while(h)
    {
      pom1[h->zac].poc++; pom1[h->zac].qu=h->qu; pom1[h->zac].hr=h;
      pom2[h->kon].poc++; pom2[h->kon].qu=h->qu; pom2[h->kon].hr=h;
//      if(!pom1[h->kon].poc) konec=h->kon; // Pro precislovani
      h=h->dal;
    }
    /*!!!!!!!!!!!!!!!!!!!!!*/
//    for(i=1;i<maxu;i++) fprintf(file,"%d:(%d,%d) ",i,pom1[i].poc,pom2[i].poc);
    /*!!!!!!!!!!!!!!!!!!!!!*
    h=hpoc;
    while(h)
    {
      if(pom1[h->zac].poc==1 && pom2[h->zac].poc==1)
      { h->presk=1; /*pouz[h->zac]=0;/** } else h->presk=0;
      if(pom1[h->kon].poc==1 && pom2[h->kon].poc==1)
      { h->pok=1; /*pouz[h->kon]=0;/** } else h->pok=0;
      /*!!!!!!!!!!!!!!!!!!!!!*/
//      fprintf(file,"zac:%d kon:%d presk:%d pok:%d \n",h->zac,h->kon,h->presk,h->pok);
      /*!!!!!!!!!!!!!!!!!!!!!*
      h=h->dal;
    }

    // Precislujeme vrcholy grafu, aby to vypadalo lepe

/*    zamena[konec]=maxu;
    pouz[konec]=0;
    for(i=1;i<maxu;i++)
      if(!pouz[i])
	for(int j=konec+1;j<maxu;j++)
	  if(pouz[j] && !zamena[j])
	  { zamena[j]=i; zamena[i]=j; pouz[i]=1; break; }
    h=hpoc;
    while(h)
    {
      if(zamena[h->zac]) h->zac=zamena[h->zac];
      if(zamena[h->kon]) h->kon=zamena[h->kon];
      h=h->dal;
    }
    delete pouz;
    delete zamena;
    /**

    // Vytiskneme graf

    //volnapamet("Pre vypisem");
    h=hpoc;
    while(h)
    {
      if(!h->presk)
      {
	QFILE<<"-"<<h->zac<<"- ";
	h->qu->vstrom()->test3(file);
	QFILE<<" ";
	Hrana* g=h;
	while(g->pok)
	{
	  g=pom1[g->kon].hr;
	  QFILE<<"+ ";
	  g->qu->vstrom()->test3(file);
	  QFILE<<" ";
	}
	QFILE<<"-"<<g->kon<<"-"<<endl;
      }
      h=h->dal;
    }
    delete pom1; delete pom2;
  } else {
    Hrana* h=hpoc;
    while(h)
    {
      QFILE<<"-"<<h->zac<<"- ";
      h->qu->vstrom()->test3(file);
      QFILE<<" -"<<h->kon<<"-"<<endl;
      h=h->dal;
    }
  }
  //volnapamet("Po vypisu");
  Hrana *h=hpoc,*g;
  while(h)
  {
    g=h->dal;
    h->qu->npouz(0);
    h->qu->nurov(0);
    delete h;
    h=g;
  }
  //if(vstup) { puts("/"); vstup->test2(file,pospojovat); }
  //volnapamet("Uplny konec vypisu");
}

void Qpravidlo::test(FILE* file)
{
  QFILE<<"("<<vid()<<")  ";
  lretez->test(file);
  QFILE<<" == ";
  pretez->test(file);
  if(podm) { QFILE<<" / "; podm->test(file); }
  QFILE<<" ."<<endl;
}

void Qfaze::test(FILE* file)
{
  QFILE<<endl<<"**    F A Z E  ( "<<vid()<<" )  **."<<endl;
  Qpravidlo* p=prav;
  while(p) { p->test(file); p=p->dal(); }
}

void Qprogram::test(FILE* file)
{
  Qfaze* f=_faze;
  while(f) { f->test(file); f=f->dal(); }
}

void Qdisjunkce::test(FILE* file)
{
  p1->test(file);
  QFILE<<" -OU- ";
  p2->test(file);
}

void Qkonjunkce::test(FILE* file)
{
  p1->test(file);
  QFILE<<" -ET- ";
  p2->test(file);
}

void Qnegace::test(FILE* file)
{
  QFILE<<" -NON- ";
  p->test(file);
}

void Qrovnost::test(FILE* file)
{
  u1->test(file);
  QFILE<<" = ";
  u2->test(file);
}

void Qnerovnost::test(FILE* file)
{
  u1->test(file);
  QFILE<<" \" ";
  u2->test(file);
}

void Qdans::test(FILE* file)
{
  u1->test(file);
  QFILE<<" -DANS- ";
  u2->test(file);
}

void Qhors::test(FILE* file)
{
  u1->test(file);
  QFILE<<" -HORS- ";
  u2->test(file);
}

void Qvstup::test1(FILE* f)
{
  vhrana()->test4(f);
  if(dalsi())
  {
    QFILE<<"*** DALSI VSTUP ***"<<endl<<endl;
    dalsi()->test1(f);
  }
}

void Qvstup::test2old(FILE* f)
{
  vhrana()->test2(f);
  if(dalsi())
  {
    QFILE<<endl<<"/"<<endl<<endl;
    dalsi()->test2(f);
  }
}

Qpravidlo* Qfaze::pravidloid(int n)
{
  Qpravidlo* f=pravidlo();
  while(f)
  {
    if(f->vid()==n) return f;
    f=f->dal();
  }
  return NULL;
}

Qfaze* Qprogram::fazeid(int n)
{
  Qfaze* f=faze();
  while(f)
  {
    if(f->vid()==n) return f;
    f=f->dal();
  }
  return NULL;
}

void Qprogram::pripoj(Qprogram *prg){
  Qfaze *f=faze();
  if(f){
    while(f->dal()) f=f->dal();
    f->nastav(prg->faze());
  }else{
    _faze=prg->faze();
  }
  prg->nfaze(NULL);
  delete prg;
}

int Qhrana::kontrola(Prom* prom,Lseznam* ls)
{
  if(!vstrom()->kontrola(prom,ls)) return 0;
  else if(!vretez1()) return 1;
  else return vretez1()->kontrola(prom,ls);
}

int Qstrom::kontrola(Prom* prom,Lseznam* ls)
{
  Uzel* u=new Uzel(this,NULL,NULL);
  malopameti(u);
  while(u)
  {
    Uzel* v=u->vdal();
    Qstrom* tqu=(!u->vstr()->vdesint() ? u->vstr() : u->vstr()->vdesint());
    if(tqu->promenna() && !prom->existuje(tqu->vobsah()))
     { schyba("Neznama promenna",ls); return 0; }
    //if(!u->vqu()->light() && u->vqu()->vretez1()) { v=new Uzel(u->vqu()->vretez1(),v); malopameti(v); }
    if(u->vstr()->vbratr()) { v=new Uzel(u->vstr()->vbratr(),NULL,v); malopameti(v); }
    if(u->vstr()->vsyn()) { v=new Uzel(u->vstr()->vsyn(),NULL,v); malopameti(v); }
    delete u;
    u=v;
  }
  //delete prom;
  return 1;
}

int test_pravidla(Qhrana* ql,Qhrana* qp,Qpodminka* podm,Lseznam* ls)
{
  Prom* prom=NULL;
  Uzel* u=new Uzel(NULL,ql,NULL); malopameti(u);
  while(u)
  {
    Uzel* v=u->vdal();
    if(u->vstr()->vdesint()) { prom=new Prom(u->vstr()->vdesint()->vobsah(),prom); malopameti(prom); }
    else if(u->vstr()->vkonst()) { prom=new Prom(u->vstr()->vobsah(),prom); malopameti(prom); }
    if(u->vhrn() && u->vhrn()->vretez1()) { v=new Uzel(NULL,u->vhrn()->vretez1(),v); malopameti(v); }
    if(u->vstr()->vbratr()) { v=new Uzel(u->vstr()->vbratr(),NULL,v); malopameti(v); }
    if(u->vstr()->vsyn()) { v=new Uzel(u->vstr()->vsyn(),NULL,v); malopameti(v); }
    delete u;
    u=v;
  }
/*  u=new Uzel(qp,NULL);
  malopameti(u);
  while(u)
  {
    Uzel* v=u->vdal();
    Quzel* tqu=(!u->vqu()->vdesint() ? u->vqu() : u->vqu()->vdesint());
    if(tqu->promenna() && !prom->existuje(tqu->vobsah()))
     { delete prom; delete ql; delete qp; if(podm) delete podm; schyba("Neznama promenna",ls); return 0; }
    if(!u->vqu()->light() && u->vqu()->vretez1()) { v=new Uzel(u->vqu()->vretez1(),v); malopameti(v); }
    if(u->vqu()->vbratr1()) { v=new Uzel(u->vqu()->vbratr1(),v);  malopameti(v); }
    if(u->vqu()->vsyn1()) { v=new Uzel(u->vqu()->vsyn1(),v);  malopameti(v); }
    delete u;
    u=v;
  } /**
  if(!qp->kontrola(prom,ls) || podm && !podm->kontrola(prom,ls))
   { delete prom; delete ql; delete qp; if(podm) delete podm; schyba("Neznama promenna",ls); return 0; }
  delete prom;/**
  return 1;
}/**/

